using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using ErkerTech.DeltaScope.View.Models;
using ErkerTech.DeltaScope.View.Common;

namespace ErkerTech.DeltaScope.View.Controls
{
    public class BlockHistogram : BaseControl
    {
        #region Private Declarations
        private const Container components = null;
        private Color _leftColor, _rightColor;
        private IList<SwirlBlock> _blocks;
        private double _pixelsPerLine;
        private Bitmap _buffer;
        private RectangleF[] _leftRects;
        private RectangleF[] _rightRects;
        private int _currentBlock = -1;
        #endregion

        #region Public Properties
        public IList<SwirlBlock> Blocks
        {
            get { return _blocks; }
            set 
            {
                if (_blocks == value) return;
                _blocks = value; 
                if (_blocks == null)
                {
                    _leftRects = null;
                    _rightRects = null;
                }
                else
                {
                    _leftRects = new RectangleF[_blocks.Count];
                    _rightRects = new RectangleF[_blocks.Count];
                }
                Invalidate();
            }
        }
        public int CurrentBlockIndex { get {return _currentBlock;} }
        public Color LeftColor
        {
            get { return _leftColor; }
            set { _leftColor = value; }
        }
        public Color RightColor
        {
            get { return _rightColor; }
            set { _rightColor = value; }
        }
        #endregion

        public BlockHistogram()
        {
            InitializeComponent();		

            // Only subscribe to these events during run-time...
            if ((Site != null) && ((Site == null) || (Site.DesignMode != false))) return;
            
            Paint += BlockHistogramPaintHandler;
            MouseEnter += BlockHistogram_MouseEnter;
            MouseMove += BlockHistogram_MouseMove;
            MouseLeave += BlockHistogram_MouseLeave;
        }

        public override sealed ISite Site
        {
            get { return base.Site; }
            set { base.Site = value; }
        }

        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            // Let the invalidate command continue...
            base.OnInvalidated (e);

            // If there is a container and we are not in design mode, then Paint the to the bitmap...
            if ((Site != null) && (Site.DesignMode)) return;

            // Create the newly sized bitmap...
            if (DisplayRectangle.Width == 0 || DisplayRectangle.Height == 0) return;
            _buffer = new Bitmap(DisplayRectangle.Width, DisplayRectangle.Height);

            var loTemp = Graphics.FromImage(_buffer);
            DrawBlocks(loTemp);
            loTemp.Dispose();
        }

        #region Component Designer generated code
        protected override void Dispose( bool disposing )
        {
            if (( disposing ) && (components != null)) components.Dispose();
            base.Dispose( disposing );
        }

        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            BackColor = System.Drawing.Color.Black;
            Name = "BlockHistogram";
            Size = new System.Drawing.Size(392, 72);
        }
        #endregion

        private void BlockHistogramPaintHandler(object sender, PaintEventArgs e)
        {
            if (_blocks != null) e.Graphics.DrawImageUnscaled(_buffer, DisplayRectangle);
        }
		
        protected int MaxNumberOfLines
        {
            get 
            {
                var lnReturn = 0;
                foreach (var block in _blocks)
                {
                    if (block.LeftSide.ALines.Length > block.RightSide.ALines.Length)
                        lnReturn += block.LeftSide.ALines.Length;
                    else
                        lnReturn += block.RightSide.ALines.Length;
                }
                return lnReturn;
            }
        }
        private void DrawBlocks(Graphics toGraphics)
        {
            if (_blocks == null) return;
            if (_blocks.Count <= 0) return;

            var lnMaxLineCount = MaxNumberOfLines;
	
            _pixelsPerLine = (double)DisplayRectangle.Width / lnMaxLineCount;
			
            // Get the 2 color pens...
            var loLeftPen = new Pen(_leftColor);
            var loRightPen = new Pen(_rightColor);

            // Setup the 2 arrays of rectangles to draw...
            var lnBlockCount = _blocks.Count;

            // Loop through all the blocks...
            SwirlBlock loBlock;
            var lnPrevRight = 0F;
            var lnDispHeight = DisplayRectangle.Height;
            for (var lnBlockIdx = 0; lnBlockIdx < lnBlockCount; lnBlockIdx++)
            {
                loBlock = _blocks[lnBlockIdx]; 				

                _leftRects[lnBlockIdx].Y = lnDispHeight * ((loBlock.IsDiffBlock) ? 0.2F: 0.4F);
                _leftRects[lnBlockIdx].Height = (lnDispHeight / 2) - _leftRects[lnBlockIdx].Y;
                _rightRects[lnBlockIdx].Y = (lnDispHeight / 2) +1; 
                _rightRects[lnBlockIdx].Height = _leftRects[lnBlockIdx].Height;

                // Figure out which X should win...
                if (lnBlockIdx>0)
                {
                    lnPrevRight = _leftRects[lnBlockIdx-1].Right > _rightRects[lnBlockIdx-1].Right 
                        ? _leftRects[lnBlockIdx-1].Right 
                        : _rightRects[lnBlockIdx-1].Right;
                }

                // Left Block...
                _leftRects[lnBlockIdx].X = lnPrevRight;
                _leftRects[lnBlockIdx].Width = loBlock.LeftSide.ALines.Length * (float)_pixelsPerLine;

                _rightRects[lnBlockIdx].X = lnPrevRight;
                _rightRects[lnBlockIdx].Width = loBlock.RightSide.ALines.Length * (float)_pixelsPerLine;	
            }

            var loLeftBrush = new SolidBrush(_leftColor);
            var loRightBrush = new SolidBrush(_rightColor);

            // Draw the rectangles...
            toGraphics.Clear(BackColor);
            toGraphics.DrawRectangles(loLeftPen, _leftRects);
            toGraphics.FillRectangles(loLeftBrush, _leftRects);
            toGraphics.DrawRectangles(loRightPen, _rightRects);
            toGraphics.FillRectangles(loRightBrush, _rightRects);

            // Draw the horizontal end-lines...
            var lnHeight = DisplayRectangle.Height;
            var loLinePen = new Pen(ForeColor);
            for (var lnCnt = 1; lnCnt < lnBlockCount; lnCnt++)
            {
                var lnX = _leftRects[lnCnt].Left;
                toGraphics.DrawLine(loLinePen, lnX, 0, lnX, lnHeight);
            }
        }

        private int _GetBlockFromPoint(Point toPoint)
        {
            // Loop through each block and do a hit test to see if the rectangle was clicked in...
            _currentBlock = -1;
			
            if (_blocks == null) return _currentBlock;

            for (var lnCnt = 0; lnCnt < _blocks.Count; lnCnt++)
            {
                try
                {
                    if (((_leftRects[lnCnt].Top <= toPoint.Y) && (_leftRects[lnCnt].Bottom >= toPoint.Y)) &&
                ((_leftRects[lnCnt].Left <= toPoint.X) && (_leftRects[lnCnt].Right >= toPoint.X)))
                        _currentBlock = lnCnt;

                    if ((_currentBlock == -1) &&
                         ((_rightRects[lnCnt].Top <= toPoint.Y) && (_rightRects[lnCnt].Bottom >= toPoint.Y)) &&
                         ((_rightRects[lnCnt].Left <= toPoint.X) && (_rightRects[lnCnt].Right >= toPoint.X)))
                        _currentBlock = lnCnt;

                    if (_currentBlock >= 0) break;
                }
                catch (System.Exception ex)
                {
                    
                  
                }
            }
            return _currentBlock;
        }

        private void BlockHistogram_MouseMove(object sender, MouseEventArgs e)
        {
            var loPoint = new Point(e.X, e.Y);
            Cursor = _GetBlockFromPoint(loPoint) >= 0 ? Cursors.Hand : Cursors.Default;
        }

        private void BlockHistogram_MouseLeave(object sender, System.EventArgs e)
        {
            Cursor = Cursors.Default;
        }

        private void BlockHistogram_MouseEnter(object sender, System.EventArgs e)
        {
            var loPoint = PointToClient(Cursor.Position);
            if (_GetBlockFromPoint(new Point(loPoint.X + 1, loPoint.Y + 1)) >= 0) Cursor = Cursors.Hand;
        }
    }
}